<template>
  <div>
    <el-row :gutter="10">
      <el-col :xs="1" :sm="1" :md="1" :lg="3" :xl="4"><div>&nbsp;</div></el-col>
      <el-col :xs="22" :sm="22" :md="22" :lg="18" :xl="16">
        <div id="editor" v-loading.fullscreen.lock="loading">
          <el-button
            size="small"
            round
            icon="el-icon-back"
            style="float: left"
            @click="goBack"
            plain
            type="success"
            >返回</el-button
          ><br />
          <el-divider style="padding: 0"
            ><el-input
              id="title"
              style="border: none; width: 420px; background-color: #ffffff00"
              prefix-icon="el-icon-set-up"
              type="text"
              placeholder="请在此输入标题~O(∩_∩)O~开始你的创作"
              v-model="title"
              maxlength="20"
              show-word-limit
            >
            </el-input
          ></el-divider>

          <el-row type="flex" justify="space-between">
            <div id="category" style="float: left">
              <el-select
                v-model="selectedCategory"
                clearable
                @change="changeCategory"
                placeholder="选择笔记类别"
                style="display: block; width: 240px"
              >
                <el-option-group
                  v-for="group in groups"
                  :key="group.label"
                  :label="group.label"
                >
                  <el-option
                    v-for="category in group.categories"
                    :key="category.value"
                    :label="category.label"
                    :value="category.value"
                  >
                    <span style="float: left; font-size: 17px"
                      ><i
                        :class="{ 'el-icon-s-order': category.value !== '0' }"
                        style="color: #008984"
                      ></i
                      >{{ category.label }}</span
                    >
                  </el-option>
                </el-option-group>
              </el-select>
            </div>

            <el-popover placement="bottom" width="600" trigger="click">
              <div id="labels" style="width: 100%">
                <el-select
                  v-model="selectedLabels"
                  style="display: block"
                  multiple
                  filterable
                  allow-create
                  default-first-option
                  @change="changeLabels"
                  placeholder="选择笔记的标签~最多5个标签~自定义标签最多10个字符~"
                >
                  <el-option
                    v-for="label in labels"
                    :key="label"
                    :label="label"
                    :value="label"
                  >
                  </el-option>
                </el-select>
              </div>
              <el-button slot="reference" round type="primary" plain style=""
                >点我(｡･ω･｡)选择标签</el-button
              >
            </el-popover>
          </el-row>
          <!-- :toolbars="toolbars" -->
          <div id="textAreaWrapper">
            <mavon-editor
              style="margin-top: 10px"
              v-model="content"
              fontSize="18px"
              :subfield="false"
              toolbarsBackground="#d8efe452"
              :toolbars="toolbars"
              @save="save"
              @imgAdd="addImg"
              @imgDel="delImg"
              boxShadowStyle="#0000008c 2px 2px 12px 0px"
              placeholder="记录你的记录~"
              :externalLink="externalLink"
              :tabSize="4"
              ref="mdEditor"
            >
              <!-- 左侧自定义工具按钮-重写CTRL Z CTRL Y按钮,为了解决修改时进页面按回退按钮会导致页面清空 -->
              <template slot="left-toolbar-before">
                <button
                  type="button"
                  @click="undo"
                  aria-hidden="true"
                  class="op-icon fa fa-mavon-undo"
                  title="上一步(ctrl+z)"
                ></button>
                <button
                  type="text"
                  @click="redo"
                  aria-hidden="true"
                  class="op-icon fa fa-mavon-repeat"
                  title="下一步(ctrl+y)"
                ></button>
              </template>
            </mavon-editor>
          </div>
          <EditorHelperComponent :visible.sync="helpDialogVisible" />

          <!-- :modal="false" -->
          <el-dialog
            title="新增类别"
            :visible.sync="dialogFormVisible"
            width="350px"
            :append-to-body="true"
            :close-on-click-modal="false"
          >
            <el-input
              v-model="category_name"
              autocomplete="off"
              maxlength="10"
              show-word-limit
              prefix-icon="el-icon-document-add"
              placeholder="在此输入类别名"
            ></el-input>
            <div slot="footer" class="dialog-footer">
              <el-button @click="dialogFormVisible = false" size="medium"
                >取 消</el-button
              >
              <el-button size="medium" type="primary" @click="addCategory" plain
                >确 定</el-button
              >
            </div>
          </el-dialog>
        </div></el-col
      >
      <el-col :xs="1" :sm="1" :md="1" :lg="3" :xl="4"><div>&nbsp;</div></el-col>
    </el-row>
  </div>
</template>

<script>
// 全局注册
// import with ES6
import Vue from "vue";
import mavonEditor from "mavon-editor";
import "mavon-editor/dist/css/index.css";
import EditorHelperComponent from "@/components/note/EditorHelperComponent.vue";
import { URLS } from "@/router";
import axios from "@/util/AxiosUtil.js";
import axiosStatic from "axios";
import apis from "@/util/ApiUrls";
// use 注册第三方组件
Vue.use(mavonEditor);
// new Vue({
//   el: "#editor",
// });
// 直接使用下面的export default即可完成初始化

export default {
  components: { EditorHelperComponent },
  name: "NotebookEditor",
  created() {
    // 获取笔记id-如果没有则是新建,否则是修改
    const id = this.$route.params.id;
    if (id) {
      console.log("修改笔记~");
      // 修改模式
      this.isUpdating = true;
      this.isUpdatingInit = true; // 首次进入修改，CTRL Z事件会被禁用，保存后或者编辑后，会退出这个状态
      this.id = id;
      this.loading = true;
      // 修改的情况下 需要获取笔记标题、内容、类别、标签
      axios
        .get(apis.api_article.note + "/?id=" + id)
        .then((res) => {
          const data = res.data;
          this.title = data.title;
          this.content = data.markdown;
          this.selectedCategory = data.categoryId;
          this.selectedLabels = data.labels;
        })
        .catch((e) => {
          this.$notify({
            title: "警告:获取笔记数据失败",
            message: e.msg,
            type: "warning",
            duration: 1500,
          });
        })
        .finally(() => {
          this.loading = false;
        });
    } else {
      console.log("新建笔记~");
      this.content = this.$route.params.content || "";
      this.title = this.$route.params.title || "";

      // 新建模式
      this.isUpdating = false;
      // 新建笔记的时候弹出提示框
      const loading = this.$loading({
        lock: true,
        text: "加载中...",
        spinner: "el-icon-loading",
        background: "#ffffffab",
      });
      setTimeout(() => {
        loading.close();
        this.helpDialogVisible = true;
      }, 1200);

      // 新建笔记时申请一个笔记id
      axios
        .post(apis.api_article.newNoteId)
        .then((id_res) => {
          this.id = id_res.data;
        })
        .catch((e) => {
          this.$notify({
            title: "错误:生成笔记id失败!后续处理不能正常进行!",
            message: e.msg,
            type: "error",
            duration: 1700,
          });
        });
    }

    // 获取类别
    axiosStatic
      .all([
        axios.get(apis.api_article.category),
        axios.get(apis.api_article.defaultLabels),
      ])
      .then(
        axiosStatic.spread((category_res, label_res) => {
          // 分类
          let categories = category_res.data;
          categories.forEach((element) => {
            this.groups[1].categories.push({
              label: element.categoryName,
              value: element.categoryId,
            });
          });

          // 标签
          this.labels = label_res.data;
        })
      )
      .catch((e) => {
        this.$notify({
          title: "警告:获取必要数据失败",
          message: e.msg,
          type: "warning",
          duration: 1500,
        });
      });
  },
  mounted() {
    // 监听CTRL + Z事件,在created中无法获取dom元素,还没有渲染
    let textArea = document.querySelector("div#textAreaWrapper textArea");
    if (textArea) {
      textArea.onkeydown = (e) => {
        // 在更新模式下没有任何编辑,初次/刚刚进入页面
        if (e.ctrlKey == true && e.keyCode == 90 && this.isUpdatingInit) {
          console.log("未进行编辑无法回退");
          //Ctrl+Z
          // 阻止事件传播
          e.stopPropagation();
        }
      };
    }
  },
  methods: {
    // 返回
    goBack() {
      this.$confirm(
        "将会返回控制台页面，所有未保存操作将会丢失，是否确认?",
        "提示",
        {
          cancelButtonText: "取消",
          confirmButtonText: "确定",
          type: "warning",
        }
      ).then(() => {
        this.$router.push({
          path: URLS.home,
          name: URLS.homeName,
        });
      });
    },
    // 刷新类别下拉菜单
    refreshCategory() {
      axios
        .get(apis.api_article.category)
        .then((res) => {
          // 分类
          let categories = res.data;
          let vo = [];
          categories.forEach((element) => {
            vo.push({
              label: element.categoryName,
              value: element.categoryId,
            });
          });
          this.groups[1].categories = vo;
        })
        .catch((e) => {
          this.$notify({
            title: "警告:刷新类别数据失败",
            message: e.msg,
            type: "warning",
            duration: 1500,
          });
        });
    },
    // 新建类别事件
    addCategory() {
      if (
        this.category_name === undefined ||
        this.category_name.trim() === ""
      ) {
        this.$message({
          message: "你还没有输入任何东西",
          type: "warning",
          duration: 1000,
        });
        return;
      }

      // 分类上限数量
      if (this.groups[1].categories.length > 25) {
        this.$notify({
          title: "警告",
          message: "每个用户最大只能创建25个分类",
          type: "warning",
          duration: 1500,
        });
        return;
      }

      this.loading = true;
      axios
        .post(apis.api_article.category, {
          categoryName: this.category_name,
          categoryId: undefined,
        })
        .then((res) => {
          // 成功后将新建的类别加入下拉菜单
          this.$message({
            message: "创建完成,现在可以使用了~",
            type: "success",
            duration: 1000,
          });
          this.dialogFormVisible = false;
          this.groups[1].categories.push({
            value: res.data,
            label: this.category_name,
          });
          // 选中刚刚创建的分类
          this.selectedCategory = res.data;
        })
        .catch((e) => {
          let msg = e.msg;
          if (e.code === 202) {
            msg = "分类已经创建过了,这里帮你重新加载了~";
            this.refreshCategory();
          }
          this.$notify({
            title: "警告",
            message: msg,
            type: "warning",
            duration: 1500,
          });
        })
        .finally(() => {
          this.loading = false;
        });
    },
    // 选标签事件
    changeLabels(currentVal) {
      const lastIndex = currentVal.length - 1;
      if (lastIndex > -1) {
        // 判断是否是默认标签
        if (this.labels.indexOf(currentVal[lastIndex]) === -1) {
          // 不是默认标签,字数不能超过10个
          if (currentVal[lastIndex].length > 10) {
            this.$notify({
              title: "警告",
              message: "自定义标签最大10个字",
              type: "warning",
              duration: 1500,
            });
            this.selectedLabels = currentVal.slice(0, lastIndex);
            return;
          }
        }
      }

      if (currentVal.length > 5) {
        this.$notify({
          title: "警告",
          message: "最多只能指定5个标签",
          type: "warning",
          duration: 1500,
        });
        this.selectedLabels = currentVal.slice(0, 5);
      }
    },
    // 切换类别
    changeCategory(currentVal) {
      if (currentVal === "0") {
        this.selectedCategory = "";
        // 新建类别
        this.dialogFormVisible = true;
        this.category_name = "";
      }
    },
    // 保存文本(md格式)
    save() {
      // 一些check
      if (this.id === undefined || this.id.trim().length === 0) {
        this.$message({
          message: "笔记数据不整合~尝试重新进入页面",
          type: "error",
          duration: 1500,
        });
      }

      if (this.title === undefined || this.title.trim().length === 0) {
        this.$message({
          message: "请输入标题~",
          type: "warning",
          duration: 1500,
        });
        return;
      }

      if (
        this.selectedCategory === undefined ||
        this.selectedCategory.trim().length === 0
      ) {
        this.$message({
          message: "请选择分类~",
          type: "warning",
          duration: 1500,
        });
        return;
      }

      if (this.content === undefined || this.content.trim().length === 0) {
        this.$message({
          message: "必须要写点什么才能保存~",
          type: "warning",
          duration: 1500,
        });
        return;
      }

      const params = {
        id: this.id,
        title: this.title,
        markdown: this.content,
        categoryId: this.selectedCategory,
        labels: this.selectedLabels,
      };
      // 提交
      this.loading = true;

      // 分支-新建或者修改
      const successHandler = () => {
        // 新建保存后变成编辑状态
        // this.isUpdating = true;
        this.$notify({
          title: "笔记已提交",
          message: "笔记已被妥善保存了~",
          type: "success",
          duration: 1500,
        });

        if (this.isUpdating) {
          // 重新进入编辑界面
          this.$router.push({
            path: URLS.edit,
            name: URLS.editName,
            params: {
              id: this.id,
            },
          });
        } else {
          // 新建成功后回到主页
          setTimeout(() => {
            this.$router.push({
              path: URLS.home,
              name: URLS.homeName,
            });
          }, 900);
        }
      };

      if (this.isUpdating) {
        // 更新
        axios
          .put(apis.api_article.note, params)
          .then(successHandler)
          .catch((e) => {
            let msg = e.msg;
            if (e.code === 201) {
              msg = "似乎受到了服务器的抗拒~再提交一次试试~";
            }
            this.$notify({
              title: "警告",
              message: msg,
              type: "warning",
              duration: 1500,
            });
          })
          .finally(() => {
            this.loading = false;
          });
      } else {
        // 新建
        axios
          .post(apis.api_article.note, params)
          .then(successHandler)
          .catch((e) => {
            let msg = e.msg;
            if (e.code === 201) {
              msg = "似乎受到了服务器的抗拒~再提交一次试试~";
            }
            this.$notify({
              title: "警告",
              message: msg,
              type: "warning",
              duration: 1500,
            });
          })
          .finally(() => {
            this.loading = false;
          });
      }
    },
    change(value, render) {
      // 编辑区发生变化的回调事件(render: value 经过markdown解析后的结果)
      if (this.isUpdating) {
        // 更新模式下, 一旦有编辑,状态变成非初始化模式,即使保存后重新进入页面，也可以继续回退了
        this.isUpdatingInit = false;
      }
    },
    undo() {
      // 回退
      let textArea = document.querySelector("div#textAreaWrapper textArea");
      // 模拟CTRL Z
      const ctrlZ = new KeyboardEvent("keydown", {
        bubbles: true,
        cancelable: true,
        keyCode: 90,
        ctrlKey: true,
      });
      textArea.dispatchEvent(ctrlZ);
    },
    redo() {
      // 恢复
      let textArea = document.querySelector("div#textAreaWrapper textArea");
      // 模拟CTRL Y
      const ctrlY = new KeyboardEvent("keydown", {
        bubbles: true,
        cancelable: true,
        keyCode: 89,
        ctrlKey: true,
      });
      textArea.dispatchEvent(ctrlY);
    },
    // 上传图片
    addImg(fileName, fileData) {
      // this.loading = true;
      // const formData = new FormData();
      // formData.append("imgFile", fileData);
      // formData.append("noteId", this.id);
      // axios
      //   .post(apis.api_file.image, formData, {
      //     headers: {
      //       "Content-Type": "multipart/form-data",
      //     },
      //     baseURL: apis.file_host,
      //   })
      //   .then((res) => {
      //     const tempUrl = apis.file_host + res.data;
      //     this.$refs.mdEditor.$img2Url(fileName, tempUrl);
      //     // 添加新增图片,为了用户上传了但是不保存的处理-后台会进行删除
      //     this.addedImages.push(
      //         tempUrl.substring(tempUrl.lastIndexOf("/") + 1)
      //       );
      //   })
      //   .catch((e) => {
      //     this.$notify({
      //       title: "警告",
      //       message: "文件上传失败:" + e.msg,
      //       type: "warning",
      //       duration: 1500,
      //     });
      //   })
      //   .finally(() => {
      //     this.loading = false;
      //   });
    },
    // 删除图片
    delImg(pos) {
      // http://localhost:9002/images/image/1/N00000000120220326094901480/20220326094907655.jpg
      // console.log(pos[0].substring(pos[0].lastIndexOf("/")));
      // const fileName = pos[0].substring(pos[0].lastIndexOf("/") + 1);
      // axios
      //   .post(apis.api_article.deleteImage, {
      //     id: this.id,
      //     deletedImages: [fileName],
      //   })
      //   .then(() => {
      //     // 如果是新增加的图片被删除了，那么同步删除新增加的图片
      //     if (this.addedImages.indexOf(fileName) != -1) {
      //       this.addedImages.splice(this.addedImages.indexOf(fileName), 1);
      //     }
      //   })
      //   .catch((e) => {
      //     console.log(e);
      //   });
    },
  },
  data() {
    return {
      isUpdating: false, // 是否处于修改模式
      isUpdatingInit: false, // 是否处于修改模式下初次进入页面,这个变量用于修复初次进修改时直接ctrl z导致的文档被清空问题
      id: "", // 笔记id, 新建是会请求一个,修改时有上一个页面传入
      loading: false,
      category_name: "", // 新增的类别名
      dialogFormVisible: false, // 类别弹框
      helpDialogVisible: false, // 帮助弹框是否显示
      title: "", // 标题
      content: "", // md内容
      selectedLabels: [
        // 选中的标签
      ],
      labels: [
        // 标签选项
      ],
      groups: [
        {
          categories: [
            {
              // 新建
              value: "0",
              label: "+ 新建 + ",
            },
          ],
        },
        {
          label: "已有类别",
          categories: [],
        },
      ],
      selectedCategory: "",
      externalLink: {
        markdown_css: function () {
          // 这是你的markdown css文件路径
          return (
            process.env.VUE_APP_PUBLIC_PATH +
            "static/md/github-markdown.min.css"
          ); // 部署时需要把这里的路径添加前缀/notebook-web-app/
        },
        hljs_js: function () {
          // 这是你的hljs文件路径
          return process.env.VUE_APP_PUBLIC_PATH + "static/md/highlight.min.js";
        },
        hljs_css: function (css) {
          // 这是你的代码高亮配色文件路径
          return (
            process.env.VUE_APP_PUBLIC_PATH +
            "static/md/styles/" +
            css +
            ".min.css"
          );
        },
        hljs_lang: function (lang) {
          // 这是你的代码高亮语言解析路径
          return (
            process.env.VUE_APP_PUBLIC_PATH +
            "static/md/languages/" +
            lang +
            ".min.js"
          );
        },
        katex_css: function () {
          // 这是你的katex配色方案路径路径
          return process.env.VUE_APP_PUBLIC_PATH + "static/md/katex.min.css";
        },
        katex_js: function () {
          // 这是你的katex.js路径
          return process.env.VUE_APP_PUBLIC_PATH + "static/md/katex.min.js";
        },
      },
      toolbars: {
        bold: true, // 粗体
        italic: true, // 斜体
        header: true, // 标题
        underline: true, // 下划线
        strikethrough: true, // 中划线
        mark: true, // 标记
        superscript: true, // 上角标
        subscript: true, // 下角标
        quote: true, // 引用
        ol: true, // 有序列表
        ul: true, // 无序列表
        link: true, // 链接
        imagelink: true, // 图片链接
        code: true, // code
        table: true, // 表格
        fullscreen: true, // 全屏编辑
        readmodel: true, // 沉浸式阅读
        htmlcode: true, // 展示html源码
        help: true, // 帮助
        /* 1.3.5 */
        undo: false, // 上一步  // 由于在编辑模式下,一进页面就按ctrl + z或者按回退按钮会导致输入内容清空，所以此处使用了自定义的按钮，直接发送CTRL Z键盘事件
        redo: false, // 下一步
        trash: true, // 清空
        save: true, // 保存（触发events中的save事件）
        /* 1.4.2 */
        navigation: true, // 导航目录
        /* 2.1.8 */
        alignleft: true, // 左对齐
        aligncenter: true, // 居中
        alignright: true, // 右对齐
        /* 2.2.1 */
        subfield: true, // 单双栏模式
        preview: true, // 预览
      },
    };
  },
};
</script>

<style>
#editor {
  height: 100%;
  background-color: #ffffffab;
  padding: 5px 20px 12px 20px;
}

/** 编辑器主体的css */
#editor .v-note-wrapper {
  height: calc(100vh - 140px);
  z-index: 10 !important;
  border-radius: 15px 15px 9px 9px !important;
  border: 2px solid #d0ede8 !important;
}
/** 工具栏的圆角 */
#editor .v-note-wrapper .v-note-op {
  border-radius: 15px 15px 0 0 !important;
  border-bottom: 2px solid #e3dfc9;
}
/** 预览框 */
#editor .v-note-show .v-show-content {
  font-size: 17px;
  font-family: Menlo, "Ubuntu Mono", Consolas, "Courier New", "Microsoft Yahei",
    "Hiragino Sans GB", "WenQuanYi Micro Hei", sans-serif;
}

#editor .el-divider__text {
  border-radius: 13px !important;
  padding: 0;
}

#editor #title {
  border-radius: 13px;
  background-color: #f2faf64d;
  font-size: 17px;
  font-weight: 400;
}

#editor #category input {
  background-color: #f2faf6;
  height: 40px;
  border: 2px solid #66c7c1;
  border-radius: 10px;
  font-weight: 600;
  font-size: 15px;
}

#editor .el-input .el-input__count .el-input__count-inner {
  background-color: #fff0 !important;
}
</style>
